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