View Javadoc
1 /* 2 * Copyright (c) 2003 Scott Howlett & Paul Libbrecht. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in 14 * the documentation and/or other materials provided with the 15 * distribution. 16 * 17 * 3. The end-user documentation included with the redistribution, 18 * if any, must include the following acknowledgment: 19 * "This product includes software developed by the Xwing 20 * Project ( http://xwing.sourceforge.net/ )." 21 * Alternately, this acknowledgment may appear in the software itself, 22 * if and wherever such third-party acknowledgments normally appear. 23 * 24 * 4. The name "Xwing" must not be used to endorse or promote products 25 * derived from this software without prior written permission. For 26 * written permission, please contact the project authors via 27 * the Xwing project site, http://xwing.sourceforge.net/ . 28 * 29 * 5. Products derived from this software may not be called "Xwing", 30 * nor may "Xwing" appear in their name, without prior written 31 * permission of the Xwing project. 32 * 33 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 34 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 35 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 36 * DISCLAIMED. IN NO EVENT SHALL THE XWING AUTHORS OR THE PROJECT 37 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 38 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 39 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 40 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 41 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 42 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 43 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 44 * SUCH DAMAGE. 45 * 46 * For more information on Xwing, please see 47 * < http://xwing.sourceforge.net/ >. 48 */ 49 50 package net.sourceforge.xwing.dom; 51 52 import java.util.Iterator; 53 import java.util.Vector; 54 55 import javax.swing.SwingUtilities; 56 import javax.swing.event.TreeModelEvent; 57 import javax.swing.event.TreeModelListener; 58 import javax.swing.tree.TreeModel; 59 import javax.swing.tree.TreePath; 60 61 62 import org.w3c.dom.Node; 63 import org.w3c.dom.events.Event; 64 import org.w3c.dom.events.EventListener; 65 import org.w3c.dom.events.EventTarget; 66 67 public class XTreeModel implements TreeModel { 68 69 private XTreeTemplate template = null; 70 private Node domRoot = null; 71 private XTreeNode instanceRoot = null; 72 73 private Vector listeners = new Vector(); 74 75 private EventListener realHandler = new EventListener() { 76 77 public void handleEvent(Event evt) { 78 try { 79 SwingUtilities.invokeLater(new Runnable() { 80 public void run() { 81 try { 82 rebuild(false); 83 } catch (Exception exc) { 84 // Swallow 85 exc.printStackTrace(); 86 } 87 } 88 }); 89 } catch (Exception exc) { 90 // swallow 91 exc.printStackTrace(); 92 } 93 } 94 }; 95 96 private EventListener handler = new WeakEventListener(realHandler); 97 98 public XTreeModel() { 99 } 100 101 public XTreeModel(XTreeTemplate pTemplate, Node pInstanceRoot) { 102 setNode(pInstanceRoot); 103 setTemplate(pTemplate); 104 } 105 public synchronized void setTemplate(XTreeTemplate pTemplate) { 106 template = pTemplate; 107 try { 108 rebuild(true); 109 } catch (Exception exc) { 110 // swallow 111 exc.printStackTrace(); 112 } 113 } 114 public synchronized void setNode(Node pNode) { 115 if (domRoot != null) { 116 EventTarget evt = (EventTarget) domRoot; 117 evt.removeEventListener("DOMSubtreeModified", handler, false); 118 } 119 domRoot = pNode; 120 if (domRoot != null) { 121 EventTarget evt = (EventTarget) domRoot; 122 evt.addEventListener("DOMSubtreeModified", handler, false); 123 } 124 try { 125 rebuild(true); 126 } catch (Exception exc) { 127 // swallow 128 exc.printStackTrace(); 129 } 130 } 131 private synchronized void rebuild(boolean force) throws Exception { 132 if (template != null) { 133 XTreeNode newRoot = null; 134 newRoot = new XTreeNode(template, domRoot); 135 if (force || instanceRoot == null) { 136 instanceRoot = newRoot; 137 fireTreeStructureChanged(); 138 } else { 139 ChangeInfo info = instanceRoot.describeChanges(newRoot, this); 140 updateTree(info, instanceRoot, newRoot); 141 } 142 } 143 } 144 public synchronized Object getRoot() { 145 return instanceRoot; 146 } 147 public synchronized Object getChild(Object parent, int index) { 148 return tn(parent).getChildAt(index); 149 } 150 public synchronized int getChildCount(Object parent) { 151 return tn(parent).getChildCount(); 152 } 153 public synchronized boolean isLeaf(Object node) { 154 return node == null ? true : tn(node).isLeaf(); 155 } 156 public synchronized void valueForPathChanged( 157 TreePath path, 158 Object newValue) { 159 fireTreeStructureChanged(); 160 } 161 private synchronized void fireTreeStructureChanged() { 162 Object newRoot = instanceRoot; 163 Object[] path = new Object[1]; 164 165 path[0] = newRoot; 166 167 TreeModelEvent e = new TreeModelEvent(this, path); 168 169 Iterator it = listeners.iterator(); 170 while (it.hasNext()) { 171 TreeModelListener listener = (TreeModelListener) it.next(); 172 listener.treeStructureChanged(e); 173 } 174 } 175 private synchronized void updateTree( 176 ChangeInfo info, 177 XTreeNode oldRoot, 178 XTreeNode newRoot) { 179 switch (info.getStatus()) { 180 case ChangeInfo.SAME : 181 { 182 XTreeNode parent = info.getChangeRoot(); 183 if (parent != null) { 184 int[] indexes = info.getChildIndices(); 185 if (indexes == null) { 186 oldRoot.setName(parent.getName()); 187 } else { 188 Object[] children = info.getChildren(); 189 for (int i = 0; i < indexes.length; ++i) { 190 parent.getChildAt(indexes[i]).setName( 191 ((XTreeNode) children[i]).getName()); 192 } 193 } 194 fireTreeEvent(info); 195 } 196 } 197 break; 198 case ChangeInfo.ADDS : 199 { 200 int[] indexes = info.getChildIndices(); 201 Object[] children = info.getChildren(); 202 XTreeNode parent = info.getChangeRoot(); 203 for (int i = 0; i < indexes.length; ++i) { 204 parent.addChild(indexes[i], (XTreeNode) children[i]); 205 } 206 fireTreeEvent(info); 207 } 208 break; 209 case ChangeInfo.DELETES : 210 { 211 int[] indexes = info.getChildIndices(); 212 XTreeNode parent = info.getChangeRoot(); 213 for (int i = indexes.length - 1; i >= 0; --i) { 214 parent.removeChild(indexes[i]); 215 } 216 } 217 fireTreeEvent(info); 218 break; 219 case ChangeInfo.COMPLEX : 220 default : 221 XTreeNode changeRoot = info.getChangeRoot(); 222 223 if (changeRoot == instanceRoot) { 224 instanceRoot = newRoot; 225 } else { 226 XTreeNode other = info.getNewChangeRoot(); 227 changeRoot.getParent().replaceChild(changeRoot, other); 228 229 } 230 fireTreeEvent(info); 231 break; 232 } 233 Vector contentChanges = info.getContentChanges(); 234 if (contentChanges != null) { 235 for (int i = 0; i < contentChanges.size(); ++i) { 236 ChangeInfo ci = (ChangeInfo) contentChanges.get(i); 237 updateTree(ci, oldRoot, newRoot); 238 } 239 } 240 } 241 private synchronized void fireTreeEvent(ChangeInfo info) { 242 TreeModelEvent e = makeEvent(info); 243 int status = info.getStatus(); 244 Iterator it = listeners.iterator(); 245 while (it.hasNext()) { 246 TreeModelListener listener = (TreeModelListener) it.next(); 247 switch (status) { 248 case ChangeInfo.SAME : 249 listener.treeNodesChanged(e); 250 break; 251 case ChangeInfo.ADDS : 252 listener.treeNodesInserted(e); 253 break; 254 case ChangeInfo.DELETES : 255 listener.treeNodesRemoved(e); 256 break; 257 case ChangeInfo.COMPLEX : 258 listener.treeStructureChanged(e); 259 break; 260 default : 261 break; 262 } 263 } 264 } 265 private synchronized TreeModelEvent makeEvent(ChangeInfo info) { 266 int status = info.getStatus(); 267 if (status == ChangeInfo.COMPLEX) { 268 XTreeNode root = info.getNewChangeRoot(); 269 Object[] path = root.getPath().toArray(); 270 return new TreeModelEvent(root, path); 271 } else { 272 XTreeNode root = info.getChangeRoot(); 273 Object[] path = root.getPath().toArray(); 274 return new TreeModelEvent( 275 root, 276 path, 277 info.getChildIndices(), 278 info.getChildren()); 279 } 280 } 281 282 public synchronized int getIndexOfChild(Object parent, Object child) { 283 return tn(parent).getIndex(tn(child)); 284 } 285 public synchronized void addTreeModelListener(TreeModelListener l) { 286 listeners.add(l); 287 } 288 public synchronized void removeTreeModelListener(TreeModelListener l) { 289 listeners.remove(l); 290 } 291 private synchronized XTreeNode tn(Object obj) { 292 return (XTreeNode) obj; 293 } 294 295 protected synchronized void finalize() throws Throwable { 296 EventTarget evt = (EventTarget) domRoot; 297 evt.removeEventListener("DOMSubtreeModified", handler, false); 298 super.finalize(); 299 } 300 }

This page was automatically generated by Maven