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