001/* 002 * Copyright 2010-2015 Institut Pasteur. 003 * 004 * This file is part of Icy. 005 * 006 * Icy is free software: you can redistribute it and/or modify 007 * it under the terms of the GNU General Public License as published by 008 * the Free Software Foundation, either version 3 of the License, or 009 * (at your option) any later version. 010 * 011 * Icy is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 014 * GNU General Public License for more details. 015 * 016 * You should have received a copy of the GNU General Public License 017 * along with Icy. If not, see <http://www.gnu.org/licenses/>. 018 */ 019package icy.gui.component.model; 020 021import icy.util.StringUtil; 022 023import java.util.ArrayList; 024import java.util.List; 025 026import javax.swing.event.EventListenerList; 027import javax.swing.event.TreeModelEvent; 028import javax.swing.event.TreeModelListener; 029import javax.swing.tree.TreeModel; 030import javax.swing.tree.TreePath; 031 032import org.w3c.dom.Document; 033import org.w3c.dom.Element; 034import org.w3c.dom.NamedNodeMap; 035import org.w3c.dom.Node; 036import org.w3c.dom.NodeList; 037 038/** 039 * @author Stephane 040 */ 041public class XMLTreeModel implements TreeModel 042{ 043 public static class XMLAdapterNode 044 { 045 public Node node; 046 047 /** 048 * Creates a new instance of the XMLAdapterNode class 049 */ 050 public XMLAdapterNode(Node node) 051 { 052 super(); 053 054 this.node = node; 055 } 056 057 /** 058 * Return all children 059 */ 060 public List<Node> getChildren() 061 { 062 final List<Node> result = new ArrayList<Node>(); 063 064 if (node.hasAttributes()) 065 { 066 final NamedNodeMap attributes = node.getAttributes(); 067 final int count = attributes.getLength(); 068 069 for (int i = 0; i < count; i++) 070 result.add(attributes.item(i)); 071 } 072 073 final NodeList nodes = node.getChildNodes(); 074 final int count = nodes.getLength(); 075 076 for (int i = 0; i < count; i++) 077 { 078 final Node node = nodes.item(i); 079 080 if (node instanceof Element) 081 result.add(node); 082 } 083 084 return result; 085 } 086 087 /** 088 * Return index of child in this node. 089 * 090 * @param child 091 * The child to look for 092 * @return index of child, -1 if not present (error) 093 */ 094 public int index(XMLAdapterNode child) 095 { 096 int result = 0; 097 098 for (Node node : getChildren()) 099 { 100 if (child.node == node) 101 return result; 102 103 result++; 104 } 105 106 return -1; // Should never get here. 107 } 108 109 /** 110 * Returns an adapter node given a valid index found through 111 * the method: public int index(XMLAdapterNode child) 112 * 113 * @param index 114 * find this by calling index(XMLAdapterNode) 115 * @return the desired child 116 */ 117 public XMLAdapterNode child(int index) 118 { 119 final Node n = getChildren().get(index); 120 121 if (n == null) 122 return null; 123 124 return new XMLAdapterNode(n); 125 } 126 127 /** 128 * Return the number of element children for this element/node 129 * 130 * @return int number of element children 131 */ 132 public int childCount() 133 { 134 return getChildren().size(); 135 } 136 137 /** 138 * Return the value of this node from its sub text nodes 139 */ 140 protected String getValue() 141 { 142 final NodeList nodes = node.getChildNodes(); 143 final int count = nodes.getLength(); 144 String result = ""; 145 146 for (int i = 0; i < count; i++) 147 { 148 final Node node = nodes.item(i); 149 150 // text node 151 if (!(node instanceof Element)) 152 { 153 final String value = node.getNodeValue(); 154 155 if ((value != null) && !StringUtil.equals(value, "null")) 156 result += value + " "; 157 } 158 } 159 160 return result.trim(); 161 } 162 163 @Override 164 public String toString() 165 { 166 final String nodeName = node.getNodeName(); 167 final String nodeValue = node.getNodeValue(); 168 169 if (!StringUtil.isEmpty(nodeValue) && !StringUtil.equals(nodeValue, "null")) 170 return nodeName + " = " + nodeValue; 171 172 return nodeName; 173 } 174 } 175 176 protected Document document; 177 178 /** 179 * listeners 180 */ 181 protected EventListenerList listeners = new EventListenerList(); 182 183 public XMLTreeModel(Document doc) 184 { 185 super(); 186 187 if (doc == null) 188 throw new NullPointerException(); 189 190 document = doc; 191 } 192 193 @Override 194 public Object getRoot() 195 { 196 if (document.getDocumentElement() == null) 197 return null; 198 199 return new XMLAdapterNode(document.getDocumentElement()); 200 } 201 202 @Override 203 public Object getChild(Object parent, int index) 204 { 205 return ((XMLAdapterNode) parent).child(index); 206 } 207 208 @Override 209 public int getIndexOfChild(Object parent, Object child) 210 { 211 return ((XMLAdapterNode) parent).index((XMLAdapterNode) child); 212 } 213 214 @Override 215 public int getChildCount(Object parent) 216 { 217 return ((XMLAdapterNode) parent).childCount(); 218 } 219 220 @Override 221 public boolean isLeaf(Object node) 222 { 223 return ((XMLAdapterNode) node).childCount() == 0; 224 } 225 226 @Override 227 public void valueForPathChanged(TreePath path, Object newValue) 228 { 229 // ignore here 230 } 231 232 /* 233 * Use these methods to add and remove event listeners. 234 * (Needed to satisfy TreeModel interface, but not used.) 235 */ 236 237 /** 238 * Adds a listener for the TreeModelEvent posted after the tree changes. 239 * 240 * @see #removeTreeModelListener 241 * @param l 242 * the listener to add 243 */ 244 @Override 245 public void addTreeModelListener(TreeModelListener l) 246 { 247 listeners.add(TreeModelListener.class, l); 248 } 249 250 /** 251 * Removes a listener previously added with <B>addTreeModelListener()</B>. 252 * 253 * @see #addTreeModelListener 254 * @param l 255 * the listener to remove 256 */ 257 @Override 258 public void removeTreeModelListener(TreeModelListener l) 259 { 260 listeners.remove(TreeModelListener.class, l); 261 } 262 263 public void fireTreeNodesChanged(TreeModelEvent e) 264 { 265 for (TreeModelListener listener : listeners.getListeners(TreeModelListener.class)) 266 listener.treeNodesChanged(e); 267 } 268 269 public void fireTreeNodesInserted(TreeModelEvent e) 270 { 271 for (TreeModelListener listener : listeners.getListeners(TreeModelListener.class)) 272 listener.treeNodesInserted(e); 273 } 274 275 public void fireTreeNodesRemoved(TreeModelEvent e) 276 { 277 for (TreeModelListener listener : listeners.getListeners(TreeModelListener.class)) 278 listener.treeNodesRemoved(e); 279 } 280 281 public void fireTreeStructureChanged(TreeModelEvent e) 282 { 283 for (TreeModelListener listener : listeners.getListeners(TreeModelListener.class)) 284 listener.treeStructureChanged(e); 285 } 286}